﻿#include "stdafx.h"
#include "SceneMain.h"
#include "MuNetConnect.h"
#include "FboColorPick.h"
#include "PboReadPixels.h"
#include "Monster.h"
#include "Npc.h"
#include "MonsterFactory.h"

void Event_KeyState();

SceneMain::SceneMain()
{
	m_lbtnDown = false;
	m_terrain = Terrain::GetInstance();
	m_currFocusObj = nullptr;
	m_currSelectObj = nullptr;
}


SceneMain::~SceneMain()
{
}

bool SceneMain::Init()
{
	g_centerPoint.x = 14350.0f;
	g_centerPoint.y = 13450.0f;
	//g_centerPoint.x = 13550.0f;
	//g_centerPoint.y = 8945.0f;
	g_centerPoint.z = 0.0f;

	g_viewPoint.x = 0.0f;
	g_viewPoint.y = 1100.0f;
	g_viewPoint.z = 850.0f;

	bool fok;
	auto conn = MuNetConnect::GetInstance();
    conn->setListener(this);

	m_guiMain.InitWindow("main.layout");

	auto wnd = MainWin::GetInstance();
	window_size_callback(wnd->GetWidth(), wnd->GetHeight());
	m_gameObjList1.SetRootMatrixPtr(&m_camera.GetViewMatrix());

	m_playerMe.Init(conn->m_currCharacter.muCls, &m_camera, &Shaders::GetInstance()->m_sBoneModel);
	m_playerMe.m_name = conn->m_currCharacter.name;
	m_playerMe.m_level = conn->m_currCharacter.level;
	//m_playerMe.m_animate.SetAnimation(1, 0);
	m_playerMe.m_animate.SetFrameRate(8);
	m_playerMe.UseLight(2);
	m_playerMe.m_intermediateMatrices.push_back(&m_camera.GetViewMatrix());
	m_playerMe.m_cb_setMapPos = [&](POINT &cell)
	{
		m_guiMain.SetText_position(cell);
	};
	m_terrain->SetCamera(&m_camera);
	if (conn->m_currCharacter.name[0])
	{
		conn->StartPlaying(conn->m_currCharacter.name);
		m_playerMe.m_visible = false;
	}
	else
	{
		fok = m_terrain->Load(0); if (!fok) Exit("terrain load error");
		m_playerMe.CalcMapPosition({ 130, 130 });
	}
	g_scale = 8;
	//m_playerMe.m_animate.SetFrameRate(g_scale);

	return true;
}

void SceneMain::window_size_callback(int width, int height)
{
	m_viewport1.SetSize(width, height);
	m_viewport1.AspectRatio(4.0f / 3.0f);
	m_camera.Perspective(35.0, m_viewport1.m_width / (float)m_viewport1.m_height, 20, 3000);
	m_terrain->m_viewport = glm::vec4(m_viewport1.m_x, m_viewport1.m_y, m_viewport1.m_width, m_viewport1.m_height);
	Shaders::GetInstance()->m_fboColorPick.Viewport(m_viewport1.m_x, m_viewport1.m_y, m_viewport1.m_width, m_viewport1.m_height);
}

void SceneMain::mouse_button_callback(int button, int action, int mods)
{
	if (button == GLFW_MOUSE_BUTTON_LEFT)
	{
		m_lbtnDown = (action == GLFW_PRESS);
	}
}

void SceneMain::Update()
{
	Event_KeyState();
	m_viewport1.Use();
	if (m_lbtnDown)
	{
		m_terrain->m_enableMousePointTest = true;
	}
	//else
	//{
	//	m_terrain->m_enableMousePointTest = false;
	//}
	auto &fbo = Shaders::GetInstance()->m_fboColorPick;
	fbo.Clear();
	m_playerMe.Update();
	g_centerPoint = m_playerMe.GetPosition();

	m_camera.LookAt(g_centerPoint.x + g_viewPoint.z, g_centerPoint.y - g_viewPoint.z, g_viewPoint.y, g_centerPoint.x + 100, g_centerPoint.y - 100, g_centerPoint.z, 0, 0, 1);
	//m_playerMe.m_animate.SetFrameRate(g_scale);
	auto &mapPos = m_playerMe.GetMapPos();
	m_terrain->UpdateCenter(mapPos.x - 3, mapPos.y + 3);
	//地形要先绘制，进行地面坐标拾取
	m_terrain->Draw();
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	m_gameObjList1.Update();
	UINT gameObjCount = m_gameObjList1.GetCount();
	for (int i = 0; i < gameObjCount; ++i)
	{
		auto obj = (RenderObject*)m_gameObjList1.GetGameObject(i);
		fbo.Add(obj->GetBoundBox());
	}
	m_playerMe.UpdateWorldMatrix();
	//fbo.Add(&m_playerMe.m_boundBox);
	if (m_playerMe.m_visible) m_playerMe.Draw();	//添加一个加载进度场景后这里可以取消判断
	ObjectPick();
}

void SceneMain::ObjectPick()
{
	auto &fbo = Shaders::GetInstance()->m_fboColorPick;
	auto wnd = MainWin::GetInstance();
	int x = wnd->GetMouseX();
	int y = wnd->GetMouseY();
	BoundBoxObject *pickObj = nullptr;
	//RenderObject::BoundBox *boundBox = nullptr;
	//RenderSceneModels::PoseBoundBox *poseBox = nullptr;
	//RenderObject *renderObj = nullptr;
	pickObj = fbo.Pick(x - m_viewport1.m_x, wnd->GetHeight() - y);
	//fbo.Draw();
	if (pickObj)
	{
		//鼠标有指向目标
		if (m_currFocusObj != pickObj)
		{
			if (m_currFocusObj && m_currFocusObj->m_cb_focus) m_currFocusObj->m_cb_focus(false);
			m_currFocusObj = pickObj;
			if (m_currFocusObj->m_cb_focus) m_currFocusObj->m_cb_focus(true);
		}
		if (m_lbtnDown)
		{
			if (m_currSelectObj != pickObj)
			{
				if (m_currSelectObj && m_currSelectObj->m_cb_select) m_currSelectObj->m_cb_select(false);
				m_currSelectObj = pickObj;
				if (m_currSelectObj->m_cb_select) m_currSelectObj->m_cb_select(true);
			}
		}
		/*switch (pickObj->m_objType)
		{
		case BoundBoxObject::ot_poseBox:
			poseBox = (RenderSceneModels::PoseBoundBox*)pickObj;
			break;
		case BoundBoxObject::ot_boundBox:
			boundBox = (RenderObject::BoundBox*)pickObj;
			renderObj = (RenderObject*)boundBox->obj;
			if (m_currFocusObj != renderObj)
			{
				if (m_currFocusObj)
				{
					m_currFocusObj->OnFocus(false);
				}
				renderObj->OnFocus(true);
			}
			OutputInformation("pick: %s\t", boundBox->obj->m_name.c_str());
			break;
		default:
			break;
		}*/
	}
	else
	{
		//鼠标没有指向游戏对象
		if (m_currFocusObj)
		{
			//取消聚集高亮等等
			if (m_currFocusObj->m_cb_focus) m_currFocusObj->m_cb_focus(false);
			m_currFocusObj = nullptr;
		}
		if (m_lbtnDown)
		{
			//点击地面行走，如果没有点击到左右两边的黑边（当视口被裁剪时）
			if (x >= m_viewport1.m_x && x < m_viewport1.m_x + m_viewport1.m_width)
				m_playerMe.MoveToMapPosition((int)m_terrain->m_mousePoint_gl.x / 100, (int)m_terrain->m_mousePoint_gl.y / 100, -1);
		}
	}
}

void SceneMain::cb_FocusObj_monster(Monster * monster, bool focus)
{
	if (focus)
		m_guiMain.ShowTopText((char*)monster->m_name.c_str());
	else
		m_guiMain.HideTopText();
}

void SceneMain::cb_SelectObj_monster(Monster * monster, bool select)
{
	FSM::Attack attack;
	attack.attackType = 0;
	attack.target = monster;
	attack.targetId = monster->GetId();
	attack.dirIdx = m_playerMe.CalcDir(m_playerMe.GetMapPos(), monster->GetMapPos());
	m_playerMe.m_fsm->SetNextState_attack(&attack);
	//OutputInformation("select %s: %s\t", select ? "true" : "false", monster->m_name.c_str());
}

GameObject *SceneMain::GetGameObjectFromId(int id)
{
	if (id == m_playerMe.GetId())
	{
		return &m_playerMe;
	}
	else
	{
		GameObject *obj = m_gameObjList1.Find(id);
		return obj;
	}
}

void SceneMain::SetMaxLife(int num)
{
	m_playerMe.m_maxLife = num;
}

void SceneMain::SetCurrLife(int num)
{
	m_playerMe.m_life = num;
	m_guiMain.SetCurrLife(num);
}

void SceneMain::SetMaxMana(int num)
{
	m_playerMe.m_maxMana = num;
}

void SceneMain::SetCurrMana(int num)
{
	m_playerMe.m_mana = num;
	m_guiMain.SetCurrMana(num);
}

void SceneMain::cursor_position_callback(double xpos, double ypos)
{
	m_terrain->m_enableMousePointTest = true;
}

void SceneMain::on_cs_close()
{
    OutputInformation("cs connect close");
}

void SceneMain::on_gs_close()
{
    OutputInformation("gs connect close");
}

void SceneMain::on_gs_moveNotice(MuPack::MoveNotice * moveNotice)
{
    auto obj = (LifeObject*)GetGameObjectFromId(ntohs(moveNotice->gameObjId));
    if (obj)
    {
        obj->MoveToMapPosition(moveNotice->x, moveNotice->y, moveNotice->dir);
    }
}

void SceneMain::on_gs_placePlayer(MuPack::PlacePlayer * placePlayer)
{
}

void SceneMain::on_gs_placeMonster(MuPack::PlaceMonster * placeMonster)
{
    auto &ms = placeMonster->monsters;
    auto mg = MonsterFactory::GetInstance();
    Shader *shader = &Shaders::GetInstance()->m_sBoneModel;
    for (int i = 0; i < placeMonster->num; ++i)
    {
        auto obj = (LifeObject*)mg->Make(ms[i].typeIndex, &m_camera, shader);
        if (obj)
        {
            obj->SetId(ntohs(ms[i].gameObjId));
            obj->CalcMapPosition({ ms[i].x1, ms[i].y1 });
            obj->SetDir(ms[i].dir);
            switch (obj->m_lifeType)
            {
            case LifeObject::LifeType::monster:
                obj->m_boundBox.m_cb_focus = std::bind(&SceneMain::cb_FocusObj_monster, this, (Monster*)obj, _1);
                obj->m_boundBox.m_cb_select = std::bind(&SceneMain::cb_SelectObj_monster, this, (Monster*)obj, _1);
                break;
            default:
                break;
            }
            m_gameObjList1.Add(obj);
        }
    }
}

void SceneMain::on_gs_removeTarget(MuPack::RemoveTarget * rmTarget)
{
    int id;
    GameObject *obj;
    for (int i = 0; i < rmTarget->num; ++i)
    {
        id = ntohs(rmTarget->gameObjIds[i]);
        if (obj = m_gameObjList1.Find(id))
        {
            auto box = ((RenderObject*)obj)->GetBoundBox();
            if (m_currSelectObj == box) {
                m_currSelectObj = nullptr;
            }
            if (m_currFocusObj == box) {
                m_currFocusObj = nullptr;
            }
            delete obj;
        }
    }
}

void SceneMain::on_gs_changeDir(MuPack::ChangeDir * changeDir)
{
    int id = ntohs(changeDir->gameObjId);
    auto obj = (LifeObject*)GetGameObjectFromId(id);
    if (obj)
    {
        if (changeDir->noAttack)
        {
            FSM::Dir dir;
            dir.dirIdx = changeDir->dir;
            obj->m_fsm->SetNextState_dir(&dir);
        }
        else
        {
            FSM::Attack attack;
            attack.attackType = 0;
            attack.dirIdx = changeDir->dir;
            attack.target = nullptr;
            attack.targetId = changeDir->gameObjId;
            obj->m_fsm->SetNextState_attack(&attack);
        }
    }
}

void SceneMain::on_gs_setCurrLife(size_t currLife)
{
    SetCurrLife(currLife);
}

void SceneMain::on_gs_setCurrMana(size_t currMana)
{
    SetCurrMana(currMana);
}

void SceneMain::on_gs_characterInfo(MuPack::CharacterInfo * charInfo)
{
    bool fok = m_terrain->Load(charInfo->map);
    m_playerMe.m_mapNumber = charInfo->map;
    m_playerMe.CalcMapPosition({ charInfo->x, charInfo->y });
    m_playerMe.m_exp = charInfo->exp;
    m_playerMe.m_expUp = charInfo->expUp;
    m_playerMe.m_levelUpPoint = charInfo->lvUpPoint;
    m_playerMe.m_strength = charInfo->str;
    m_playerMe.m_dexterity = charInfo->dex;
    m_playerMe.m_vitality = charInfo->vit;
    m_playerMe.m_energy = charInfo->ene;
    m_playerMe.m_life = charInfo->life;
    m_playerMe.m_maxLife = charInfo->maxlife;
    m_playerMe.m_mana = charInfo->mana;
    m_playerMe.m_maxMana = charInfo->maxMana;
    m_playerMe.m_money = charInfo->money;
    m_playerMe.m_pkLevel = charInfo->pkLv;
    m_playerMe.m_visible = true;
}
